package com.testapp.bluetoothtest08.cipher.impl;


import com.testapp.bluetoothtest08.cipher.GMService;
import com.testapp.bluetoothtest08.cipher.entity.CheckData;
import com.testapp.bluetoothtest08.cipher.entity.DataIndex;
import com.testapp.bluetoothtest08.cipher.entity.JoinCheck;
import com.testapp.bluetoothtest08.cipher.entity.JoinCheckStr;
import com.testapp.bluetoothtest08.cipher.entity.ScanCodeFirstRequest;
import com.testapp.bluetoothtest08.cipher.entity.ScanCodeSecondRequest;
import com.testapp.bluetoothtest08.cipher.entity.TrackParameter;
import com.testapp.bluetoothtest08.cipher.entity.UserJoin;
import com.testapp.bluetoothtest08.cipher.entity.UserLog;
import com.testapp.bluetoothtest08.cipher.entity.UserUpdate;
import com.testapp.bluetoothtest08.cipher.tool.CheckTools;
import com.testapp.bluetoothtest08.cipher.tool.MD5;
import com.testapp.bluetoothtest08.cipher.tool.NumberTools;
import com.testapp.bluetoothtest08.cipher.tool.Parameter;
import com.testapp.bluetoothtest08.cipher.tool.UniversalTools;

import lombok.AllArgsConstructor;


import java.math.BigInteger;
import java.util.LinkedList;
import java.util.List;

@AllArgsConstructor
public class GMServiceImpl implements GMService {


    private final NumberTools numberTools = new NumberTools();
    private final Parameter parameter = new Parameter();
    private final UniversalTools universal = new UniversalTools();
    private final MD5 md5 = new MD5();
    private final CheckTools checkTools = new CheckTools();

    @Override
    public JoinCheckStr userJoin(UserJoin user){
        List<String> list = new LinkedList<>();
        list.add(parameter.B.toString());
        list.addAll(parameter.Qrn.QRListStr);
        list.addAll(user.y);
        BigInteger[] baseList= {new BigInteger(user.y.get(0)),parameter.B};
        String [] exponentList = {user.c,user.s.get(0)};
        list.add(numberTools.modPowList(baseList,exponentList,parameter.Sigma).toString());
        baseList[0] = new BigInteger(user.y.get(1));
        exponentList[1] = user.s.get(1);
        list.add(numberTools.modPowList(baseList,exponentList,parameter.Sigma).toString());
        user.s.set(0,"1");
        user.s.set(1,user.c);
        List<BigInteger> bL = (List<BigInteger>)parameter.Qrn.QRList.clone();
        bL.add(1,new BigInteger(user.y.get(2)));
        list.add(numberTools.modPowList( bL.toArray(new BigInteger[bL.size()]),user.s.toArray(new String[user.s.size()]),parameter.N).toString());
        String c_ = md5.start(universal.combineString(list));
        c_ = new BigInteger(c_,16).toString(2).substring(0,Parameter.k-1);
        c_ = new BigInteger(c_,2).toString();
        if (user.c.equals(c_)){
            JoinCheck re = new JoinCheck();
            re.t2 = numberTools.generateNum(DataIndex.INDEX_T2);
            if (re.t2.mod(Parameter.bigTwo).equals(Parameter.bigZero)){
                re.t2 = re.t2.add(Parameter.bigOne);
            }
            re.y = numberTools.generateY();
            BigInteger y_inv;
            y_inv = re.y.modInverse(parameter.OrderN);
            BigInteger J2 = new BigInteger(user.y.get(2)).multiply(parameter.Qrn.A).mod(parameter.N);
            BigInteger tempA = J2.multiply(parameter.Qrn.At.modPow(re.t2,parameter.N)).mod(parameter.N);
            re.a = tempA.modPow(y_inv,parameter.N);
            return new JoinCheckStr(re);
        }
        return null;
    }

    @Override
    public String scanCodeFirst(ScanCodeFirstRequest requestFirst) {
        //should save  the user(RequestData)
        return numberTools.generateNum(DataIndex.INDEX_T2).toString();
    }

    public String scanCodeFirstTest(ScanCodeFirstRequest requestFirst) {
        //should save  the user(RequestData)
        String challenge = "988163586843875720144";
        return challenge;
    }

    @Override
    public Object scanCodeSecond(ScanCodeFirstRequest requestFirst, ScanCodeSecondRequest requestSecond, String challenge, UserLog userLog){
        CheckData checkData = checkTools.checkSPK2(requestFirst,requestSecond,challenge);
        checkTools.checkS(checkData);
        checkTools.checkR(requestSecond,checkData);
        checkTools.checkSN(requestSecond,checkData);
        if(requestSecond.c.equals(userLog.c2)){
            TrackParameter trackParameter = checkTools.computerST(new BigInteger(requestSecond.R1),new BigInteger(userLog.r1_),new BigInteger(requestSecond.c),new BigInteger(userLog.c2),new BigInteger(userLog.ic));
            return trackParameter;
        }
        return new UserLog(requestSecond.R1,requestSecond.c,requestFirst.ic,requestFirst.SN);
    }

    @Override
    public boolean scanCodeSecondJustCheck(ScanCodeFirstRequest requestFirst, ScanCodeSecondRequest requestSecond, String challenge){
        CheckData checkData = checkTools.checkSPK2(requestFirst,requestSecond,challenge);
        checkTools.checkS(checkData);
        checkTools.checkR(requestSecond,checkData);
        checkTools.checkSN(requestSecond,checkData);
        return true;
    }

    @Override
    public UserUpdate genenrateUpdateLog(ScanCodeFirstRequest request){                                 //generate AD,y'
        UserUpdate re = new UserUpdate();
        re.y_ = numberTools.generateY();
        BigInteger y_inv;
        y_inv = re.y_.modInverse(parameter.OrderN);
        re.AD = new BigInteger(request.D).modPow(y_inv,parameter.N);
        return re;
    }

    public static void main(String[] args) {
//        GMServiceImpl gmService = new GMServiceImpl();
//        String str = "{\"c\":\"5653589207083572844\",\"idCardNum\":\"7\",\"name\":\"7\",\"password\":\"7\",\"phoneNum\":\"7\",\"pku\":\"1382364241827013166059385169765917000947344671440159162610234\",\"s\":[\"907723286433309550057906502389788556801755655579603596316897\",\"2241082352268852838429998653985737763655024760940339908575807\",\"1632302511844222106572648631317811731470682238524085272694687\",\"319671858446951028521439332230861640116254729198999786847166521838857955154519262649253218708188869616706371047392662874\",\"2241082352268852838429998653985737763655024760940339908575807\",\"1844177256972326171074991227185458\",\"2527624179073176705562598324069854\",\"1412869610425543814840368259833106\",\"3124750319272655476740012305070832214222863960054260042922214\"],\"username\":\"7\",\"y\":[\"1382364241827013166059385169765917000947344671440159162610234\",\"24187095552998463384381543357385036798929856391331404307544\",\"97707243305646200900517905107416847261205332294537694372380412024717482202535\"]}";
//        str = "{\"c\":\"5823525493548261108\",\"idCardNum\":\"12345678\",\"name\":\"xyq\",\"password\":\"xyq\",\"phoneNum\":87654321,\"pku\":\"1382364241827013166059385169765917000947344671440159162610234\",\"s\":[\"979493495464198913688876365784813270668236901205626770741610\",\"2619314689732891701575026192109889881031567675038284788328224\",\"2861662571240317735488203205111630959650258320130831716517701\",\"300262487525369058454662572436993328092137711230081971504383538117054228788398166428710334041249534366165438538966876934\",\"2619314689732891701575026192109889881031567675038284788328224\",\"1693129514287948155292661848956079\",\"1508463213066780605110556219821298\",\"1724248237145529510467985017576624\",\"2196006236981856624452523950255440642592153512934677527613876\"],\"username\":\"xyq1\",\"y\":[\"1382364241827013166059385169765917000947344671440159162610234\",\"1144684498418188349362053042027937883201300236703015212196326\",\"22439577948284762410570062013008229175903529724488791934796449041304554626179\"]}";
//        //str = "{\"c\":\"8775014165991649047\",\"idCardNum\":\"7\",\"name\":\"7\",\"password\":\"7\",\"phoneNum\":\"7\",\"pku\":\"1382364241827013166059385169765917000947344671440159162610234\",\"s\":[\"1011176727823083278332700037187075748621508057049934936051530\",\"1645293515550217617957891317022665657303607547622872694626098\",\"2739635948470173369748807662213356507229075023773491643373878\",\"264663338572742800739383098183435106916033177002398507842686764870947941900975744826469620237329099463667855745889039584\",\"1645293515550217617957891317022665657303607547622872694626098\",\"1298675416136786724754517910570057\",\"2385101921520964138346636286642551\",\"2103901175556716847844282434147168\",\"1919741615901420578307995192565652570096381728755185124669189\"],\"username\":\"7\",\"y\":[\"1382364241827013166059385169765917000947344671440159162610234\",\"1417112839243435076487160112777440106211909630281513544553074\",\"166816130680185688618043625977681973164372818135250846513641264581212172196713\"]}";
//        JSONObject jsonObject = JSON.parseObject(str);
//        UserJoin userJoin = new UserJoin();
//        userJoin.c = jsonObject.getString("c");
//        for(int i=0;i<jsonObject.getJSONArray("y").size();i++){
//            userJoin.y.add(jsonObject.getJSONArray("y").getString(i));
//        }
//        for(int i=0;i<jsonObject.getJSONArray("s").size();i++){
//            userJoin.s.add(jsonObject.getJSONArray("s").getString(i));
//        }
//        JoinCheckStr joinCheckStr = gmService.userJoin(userJoin);
//        System.out.println(joinCheckStr);
//        str = "{\"c\":\"5823525493548261108\",\"idCardNum\":\"12345678\",\"name\":\"xyq\",\"password\":\"xyq\",\"phoneNum\":87654321,\"pku\":\"1382364241827013166059385169765917000947344671440159162610234\",\"s\":[\"979493495464198913688876365784813270668236901205626770741610\",\"2619314689732891701575026192109889881031567675038284788328224\",\"2861662571240317735488203205111630959650258320130831716517701\",\"300262487525369058454662572436993328092137711230081971504383538117054228788398166428710334041249534366165438538966876934\",\"2619314689732891701575026192109889881031567675038284788328224\",\"1693129514287948155292661848956079\",\"1508463213066780605110556219821298\",\"1724248237145529510467985017576624\",\"2196006236981856624452523950255440642592153512934677527613876\"],\"username\":\"xyq1\",\"y\":[\"1382364241827013166059385169765917000947344671440159162610234\",\"1144684498418188349362053042027937883201300236703015212196326\",\"22439577948284762410570062013008229175903529724488791934796449041304554626179\"]}";
//
//        jsonObject = JSON.parseObject(str);
//        userJoin = new UserJoin();
//        userJoin.c = jsonObject.getString("c");
//        for(int i=0;i<jsonObject.getJSONArray("y").size();i++){
//            userJoin.y.add(jsonObject.getJSONArray("y").getString(i));
//        }
//        for(int i=0;i<jsonObject.getJSONArray("s").size();i++){
//            userJoin.s.add(jsonObject.getJSONArray("s").getString(i));
//        }
//        joinCheckStr = gmService.userJoin(userJoin);
//        System.out.println(joinCheckStr);
//        //userJoin.s = ;
        MD5 md5 = new MD5();
        System.out.println(md5.start("123"));
        System.out.println(md5.start("345"));
        System.out.println(md5.start("123"));
        System.out.println(md5.start("123"));
        System.out.println(md5.start("123"));
    }

}
